home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Medal Software 2
/
Gold Medal Software Volume 2 (Gold Medal) (1994).iso
/
prog
/
adlip.arj
/
CONVERT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1988-10-14
|
23KB
|
1,066 lines
/*
CONVERT.C
27-jun-88, Marc Savary, Ad Lib Inc.
Module to convert *.ROL file to AdLib Midi file, *.MUS & *.SND
The beginning of the .MUS file contains 70 bytes
of start-up information (see convert.h file):
1: major version # of file
1: minor version # of file
4: melody identification
30: melody name
1: ticks per beat
1: beats per measure
4: length of melody, in ticks
4: length of melody's data part
4: total number of commands in melody, including NOTE-ON, NOTE-OFF,
PROGRAM-CHANGE, AFTER-TOUCH, PITCH-BEND, OVERFLOW, SYSTEM-XOR
& STOP
8: filler area, set to zero
1: sound mode: 0 == melodic, 1 == percussive
1: pitch bend range, from 1 to 12
2: basic tempo
8: filler area, set to zero
Following the header is the musical data.
The data part of the .MUS file contains midi 1.0 commands with timing
bytes of 1/tickBeat. tickBeat is the number of divisions per beat.
The relation between tickBeat, tempo (beat per minute) & frequency of
the timing counter is:
frequency = (tempo / 60) * tickBeat.
Timing bytes vary from 0 to 0xFE and precede every command. A timing
byte of 0xF8 means timing overflow with a value of 240. An overflow
byte is always followed by another overflow byte or timing byte.
Program changes refer to timbre definitions in the .SND bank file by their
relative order. While converting files, if a timbre ( ref. by it's name)
is not found in the bank file, its definition is appended to the end.
A tempo change is specified within a SYSTEM EXCLUSIVE MESSAGE:
0xF0 0x7F 00 <integer> <frac> 0xF7, where 'integer' is the integer
part of the tempo multiplier and 'frac' the fractionnal part, in 1/128.
Each voice is associated with one midi channel. In melodic mode,
channels 0 to 8 are melodic; in percussive mode, channels 0 to 5
are melodic and channels 6 to 11 are percussive.
The last MIDI command of the file is STOP ( 0xFC).
If compiling with Lattice, 'LATTICE' must be defined for MEMORY.C
and BANK.C.
With Microsoft, use the following ('MICROSOFT' must be defined for
this file and BANK.C):
cl -DMICROSOFT -AS -J -Zi /Zp1 -Ox -Gs play.c bank.c adlib.c
*/
#include "mem.h"
#include "convert.h"
#include "adlib.h"
#include "bank.h"
#include "strmidi.h"
#include "fcntl.h"
#include "stdio.h"
#ifdef MICROSOFT
#include <sys\types.h>
#include <sys\stat.h>
#define open(x,y) open(x,y,S_IWRITE)
#define setmem(x,y,z) memset(x,z,y)
#define min(x,y) ((x < y) ? x:y)
#define max(x,y) ((x > y) ? x:y)
#endif
#define NR_MELO_VOICES 9 /* in melodic mode */
#define NR_PERC_VOICES 11 /* in percussive mode */
#define BLOCK_SIZE 512 /* must be power of two !!! */
#define instrumFileExtension ".INS"
#define musicFileExtension ".ROL"
#define MAJOR_VERSION 1
#define MINOR_VERSION 0
/* type of events, decreasing in order of priority: */
#define NOTE_OFF_TP 0
#define PRESET_TP 1
#define PITCH_TP 2
#define VOLUME_TP 3
#define TEMPO_TP 4
#define NOTE_ON_TP 5
#define NR_TYPES 6
typedef int Time;
typedef
struct {
unsigned nrBytes;
unsigned size;
Handle liste;
} ListDesc;
typedef
struct {
Time time;
float tempo;
} TempoEvent;
typedef
struct {
int note;
int duree;
} NoteEvent;
typedef
struct {
Time time;
char instrumName[ 9];
char filler;
int timbreIndex;
} InstrumEvent;
typedef
struct {
Time time;
float volume;
} VolumeEvent;
typedef
struct {
Time time;
float pitch;
} PitchEvent;
typedef
struct {
char instrumName[ 9];
int params[ 26];
} TimbreDef;
typedef
struct {
long rollTime;
long rollPos;
char voice;
char used;
char type;
} Cedule;
#define NoteAtPos( vc, pos) ((NoteEvent *) *noteList[ vc].liste + pos)
#define PitchAtPos( vc, pos) ((PitchEvent *) *pitchList[ vc].liste + pos)
#define VolumeAtPos( vc, pos) ((VolumeEvent *) *volumeList[ vc].liste + pos)
#define InstrumAtPos( vc, pos) ((InstrumEvent *) *instrumList[ vc].liste + pos)
#define TempoAtPos( pos) ((TempoEvent *) *tempoList.liste + pos)
#define PitchSize( vc) ( pitchList[ vc].size)
#define InstrumSize( vc) ( instrumList[ vc].size)
#define VolumeSize( vc) ( volumeList[ vc].size)
#define TempoSize() ( tempoList.size)
#define NoteSize( vc) ( noteList[ vc].size)
ListDesc instrumList[ NR_VOICES];
ListDesc noteList[ NR_VOICES];
ListDesc pitchList[ NR_VOICES];
ListDesc volumeList[ NR_VOICES];
ListDesc tempoList;
ListDesc timbreList;
int srcTickBeat,
destTickBeat;
int beatMeasure;
char notPercusMode;
float basicTempo;
int pitchBRange;
Time duree_piece; /* length of piece */
Cedule cedList[ NR_TYPES][ NR_VOICES];
long offTime[ NR_VOICES];
long mpuTime;
char statusArray[ NR_TYPES] = { NOTE_ON_BYTE, PROG_CHANGE_BYTE,
PITCH_BEND_BYTE, AFTER_TOUCH_BYTE,
00, NOTE_ON_BYTE };
char status;
long byteCount;
long commCount;
char voiceVolume[ NR_VOICES];
int outFile;
BankPtr timbBank;
extern long ConvertTime();
main( argc, argv)
int argc;
char * argv[];
{
char buff[ 150];
if( argc < 4) {
fprintf( stderr, "\nUSE: convert <infile.rol> <bankfile.tim> <outfile.mus>");
exit( 1);
}
InitMemory( 32);
ColdInit();
timbBank = OpenBank( argv[ 2], 1);
if( NULL == timbBank) {
fprintf( stderr, "\nCannot open timbre bank file '%s'.", argv[ 2]);
exit( 1);
}
outFile = open( argv[ 3], O_WRONLY + O_RAW + O_TRUNC + O_CREAT);
if( -1 == outFile) {
fprintf( stderr, "\nUnable to open write file '%s'.", argv[ 3]);
exit( 1);
}
if( !ConvertFile( argv[ 1])) {
fprintf( stderr, "\nUnable to open read file '%s'.", argv[ 1]);
exit( 1);
}
close( outFile);
CloseBank( timbBank);
} /* main() */
ColdInit()
{
int i;
for( i = 0; i < NR_VOICES; i++) {
instrumList[ i].size = 0;
instrumList[ i].liste = NewHandle( (Size) 4);
instrumList[ i].nrBytes = 4;
noteList[ i].size = 0;
noteList[ i].liste = NewHandle( (Size) 4);
noteList[ i].nrBytes = 4;
pitchList[ i].size = 0;
pitchList[ i].liste = NewHandle( (Size) 4);
pitchList[ i].nrBytes = 4;
volumeList[ i].size = 0;
volumeList[ i].liste = NewHandle( (Size) 4);
volumeList[ i].nrBytes = 4;
}
tempoList.size = 0;
tempoList.liste = NewHandle( (Size) 4);
tempoList.nrBytes = 4;
timbreList.size = 0;
timbreList.liste = NewHandle( (Size) 4);
timbreList.nrBytes = 4;
/* Set the number of ticks per beat of the resulting conversion
( must be a multiple of the ticks/beat of the .ROL file)
This value is used for the conversion of the timing base. */
destTickBeat = DEFAULT_TICK_BEAT;
} /* ColdInit() */
/*
For doing conversion, we first load the piece, and simulate
the playing for ordering the events, using priority values when
the events occur at the same time.
*/
int ConvertFile( fileName)
char * fileName;
{
int voix, nb_voices;
Time longueur;
Cedule * ced;
struct MusHeader mHd;
extern Cedule * NextCedule();
if( ! MyLoadMelo( fileName))
return 0;
LoadTimbres();
setmem( &mHd, sizeof( struct MusHeader), 0);
write( outFile, &mHd, sizeof( struct MusHeader));
StartCedule();
while( ced = NextCedule()) {
switch( ced->type) {
case PRESET_TP: DoPreset( ced); break;
case PITCH_TP: DoPitch( ced); break;
case VOLUME_TP: DoVolume( ced); break;
case TEMPO_TP: DoTempo( ced); break;
case NOTE_ON_TP: DoNoteOn( ced); break;
case NOTE_OFF_TP: DoNoteOff( ced); break;
default: printf( "\nBad event type: %d", ced->type);
}
}
DoEndMelo();
mHd.majorVersion = MAJOR_VERSION;
mHd.minorVersion = MINOR_VERSION;
mHd.tickBeat = destTickBeat;
mHd.beatMeasure = beatMeasure;
mHd.totalTick = ConvertTime( duree_piece);
mHd.dataSize = byteCount;
mHd.nrCommand = commCount;
mHd.soundMode = !notPercusMode;
mHd.pitchBRange = pitchBRange;
mHd.basicTempo = basicTempo;
/* write header to output file: */
lseek( outFile, 0L, 0);
write( outFile, &mHd, sizeof( struct MusHeader));
} /* ConvertFile() */
/*
Start the simulation of playing a melody.
*/
StartCedule()
{
int i, j, k;
Cedule * ced;
ced = &cedList[ 0][ 0];
for( i = 0; i < NR_TYPES; i++)
for( k = 0; k < NR_VOICES; k++, ced++) {
ced->rollTime = 0;
ced->rollPos = 0;
ced->used = 0;
ced->voice = k;
ced->type = i;
}
for( k = 0; k < NR_VOICES; k++) {
CedulePreset( k, 0);
CedulePitch( k, 0);
CeduleVolume( k, 0);
offTime[ k] = 0;
CeduleNoteOn( k, 0);
}
CeduleTempo( 0);
mpuTime = 0;
status = 0;
byteCount = 0;
commCount = 0;
} /* StartCedule() */
/*
Find and return the next event with the lowest time value.
Return NULL if no more.
*/
Cedule * NextCedule()
{
Cedule * ced, * next;
long lowTime;
int type, vc;
ced = &cedList[ 0][ 0];
next = NULL;
lowTime = 0x7fffffff;
for( type = 0; type < NR_TYPES; type++)
for( vc = 0; vc < NR_VOICES; vc++, ced++) {
if( ! ced->used)
continue;
if( ced->rollTime < lowTime) {
lowTime = ced->rollTime;
next = ced;
}
}
return next;
} /* NextCedule() */
/*
Insert in the schedule list the note starting at position
'pos' of the .ROL note list of voice 'voice'
*/
CeduleNoteOn( voice, pos)
{
unsigned size;
Cedule * ced;
ListDesc * lD;
NoteEvent * nE;
ced = &cedList[ NOTE_ON_TP][ voice];
lD = ¬eList[ voice];
size = lD->size;
ced->used = 0;
nE = (NoteEvent *) *lD->liste + pos;
while( nE->note == 0 && pos < size) {
/* silences are notes of pitch == 0, and must be skiped */
offTime[ voice] += nE->duree;
nE++;
pos++;
}
if( pos < size) {
ced->rollPos = pos;
ced->rollTime = offTime[ voice];
ced->used = 1;
offTime[ voice] += nE->duree;
}
} /* CeduleNoteOn() */
CeduleNoteOff( voice, pos)
{
Cedule * ced;
ced = &cedList[ NOTE_OFF_TP][ voice];
ced->rollTime = offTime[ voice];
ced->rollPos = pos;
ced->used = 1;
} /* CeduleNoteOff() */
CedulePreset( voice, pos)
{
Cedule * ced;
InstrumEvent * iE;
if( NoteSize( voice) == 0)
return;
ced = &cedList[ PRESET_TP][ voice];
if( pos >= InstrumSize( voice))
ced->used = 0;
else {
iE = InstrumAtPos( voice, pos);
ced->rollTime = iE->time;
ced->rollPos = pos;
ced->used = 1;
}
} /* CedulePreset() */
CedulePitch( voice, pos)
{
Cedule * ced;
PitchEvent * pE;
if( NoteSize( voice) == 0)
return;
ced = &cedList[ PITCH_TP][ voice];
if( pos >= PitchSize( voice))
ced->used = 0;
else {
pE = PitchAtPos( voice, pos);
ced->rollPos = pos;
ced->rollTime = pE->time;
ced->used = 1;
}
} /* CedulePitch() */
CeduleVolume( voice, pos)
{
Cedule * ced;
VolumeEvent * vE;
if( NoteSize( voice) == 0)
return;
ced = &cedList[ VOLUME_TP][ voice];
if( pos >= VolumeSize( voice))
ced->used = 0;
else {
vE = VolumeAtPos( voice, pos);
ced->rollPos = pos;
ced->rollTime = vE->time;
ced->used = 1;
}
} /* CeduleVolume() */
CeduleTempo( pos)
{
Cedule * ced;
TempoEvent * tE;
ced = &cedList[ TEMPO_TP][ 0];
if( pos >= TempoSize())
ced->used = 0;
else {
tE = TempoAtPos( pos);
ced->rollPos = pos;
ced->rollTime = tE->time;
ced->used = 1;
}
} /* CeduleTempo() */
/*
In the normal sequencing order, a note-on must be done
on the voice & note specified by 'ced'.
Note-on command: <timing> <9n> <pitch> <volume>
where 'n' is the voice number.
*/
DoNoteOn( ced)
Cedule * ced;
{
NoteEvent * nE;
unsigned vol;
DoTiming( ced);
DoStatus( ced);
nE = NoteAtPos( ced->voice, ced->rollPos);
DoData( nE->note);
vol = max( 1, voiceVolume[ ced->voice]);
DoData( vol);
/* schedule the note-off of this note: */
CeduleNoteOff( ced->voice, ced->rollPos);
/* schedule the next note-on for this voice: */
CeduleNoteOn( ced->voice, ced->rollPos +1);
} /* DoNoteOn() */
/*
Note-off command: <timing> <9n> <pitch> <00>
where 'n' is the voice number.
*/
DoNoteOff( ced)
Cedule * ced;
{
NoteEvent * nE;
DoTiming( ced);
DoStatus( ced);
nE = NoteAtPos( ced->voice, ced->rollPos);
DoData( nE->note);
DoData( 0);
ced->used = 0;
} /* DoNoteOff() */
/*
Pitch command: <timing> <En> <pitch-low> <pitch-high>
where 'n' is the voice number.
*/
DoPitch( ced)
Cedule * ced;
{
PitchEvent * pE;
unsigned uPitch;
DoTiming( ced);
DoStatus( ced);
pE = PitchAtPos( ced->voice, ced->rollPos);
uPitch = pE->pitch * MID_PITCH;
uPitch = min( MAX_PITCH, uPitch);
DoData( uPitch);
DoData( uPitch >> 7);
CedulePitch( ced->voice, ced->rollPos +1);
} /* DoPitch() */
/*
After touch command: <timing> <An> <volume>
where 'n' is the voice number.
*/
DoVolume( ced)
Cedule * ced;
{
VolumeEvent * vE;
NoteEvent * nE;
Cedule * nCed;
unsigned volume;
vE = VolumeAtPos( ced->voice, ced->rollPos);
volume = vE->volume * MAX_VOLUME;
nCed = &cedList[ NOTE_ON_TP][ ced->voice];
if( nCed->used && nCed->rollTime == ced->rollTime) {
/* velocity (volume) is occuring in the same time than a note-on
on this voice; it will be sent with the note-on itself. ... */
;
}
else {
DoTiming( ced);
DoStatus( ced);
DoData( volume);
}
voiceVolume[ ced->voice] = volume;
CeduleVolume( ced->voice, ced->rollPos +1);
} /* DoVolume() */
/*
Preset change command: <timing> <Cn> <preset>
where 'n' is the voice number.
*/
DoPreset( ced)
Cedule * ced;
{
InstrumEvent * iE;
DoTiming( ced);
DoStatus( ced);
iE = InstrumAtPos( ced->voice, ced->rollPos);
DoData( iE->timbreIndex);
CedulePreset( ced->voice, ced->rollPos +1);
} /* DoPreset() */
/*
Tempo: <timing> <F0> <7F> <00> <integer> <frac> <F7>
(non standard)
*/
DoTempo( ced)
Cedule * ced;
{
TempoEvent * tE;
unsigned ent, frac;
tE = TempoAtPos( ced->rollPos);
ent = min( (unsigned)tE->tempo, 127);
frac = (tE->tempo - ent) * 128;
DoTiming( ced);
PutByte( SYSTEM_XOR_BYTE);
status = 0; /* status must be re-sent next time */
PutByte( ADLIB_CTRL_BYTE);
PutByte( TEMPO_CTRL_BYTE);
DoData( ent);
DoData( frac);
PutByte( EOX_BYTE);
CeduleTempo( ced->rollPos +1);
} /* DoTempo() */
/*
End melody: <timing> <FC>
*/
DoEndMelo()
{
commCount++;
PutByte( 0);
PutByte( STOP_BYTE);
} /* DoEndMelo() */
/*
Add the timing bytes. If the delay ( in "n/destTickBeat" Beats)
is greater than or equal to OVERFLOW, insert enough overflow bytes
before the timing byte.
*/
DoTiming( ced)
Cedule * ced;
{
long time;
commCount++;
time = ConvertTime( ced->rollTime);
while( time - OVERFLOW >= mpuTime) {
commCount++;
PutByte( OVERFLOW_BYTE);
mpuTime += OVERFLOW;
}
PutByte( time - mpuTime);
mpuTime = time;
} /* DoTiming() */
/*
Convert the time 'rollTime' from the base 'srcTickBeat' (.ROL) to
the base 'destTickBeat' ( .MUS)
*/
long ConvertTime( rollTime)
Time rollTime;
{
long time;
time = (long)rollTime * destTickBeat;
time /= srcTickBeat;
return time;
} /* ConverTime() */
/*
Generate a status byte for the NOTE-ON, NOTE-OFF, PRESET-CHANGE, PITCH-BEND
or AFTER-TOUCH (volume) midi command.
*/
DoStatus( ced)
Cedule * ced;
{
char newStatus;
newStatus = statusArray[ ced->type] + ced->voice;
if( newStatus != status) {
status = newStatus;
PutByte( status);
}
} /* DoStatus() */
/*
Send data byte (high bit set to 0) to output file.
*/
DoData( data)
char data;
{
PutByte( data & 0x7f);
} /* DoData() */
/*
Send byte to output file, increment byte counter.
*/
PutByte( data)
char data;
{
write( outFile, &data, 1);
byteCount++;
} /* PutByte() */
/*
-------------------------------------------------------------
The following routines are used to load a .ROL file in memory.
Allocate memory using the routines in the MEMORY.C file.
-------------------------------------------------------------
*/
SizeList( liste, nrElems, sizeElem)
ListDesc * liste;
unsigned nrElems;
unsigned sizeElem;
{
unsigned newSize;
newSize = nrElems * sizeElem;
if( newSize > liste->nrBytes) {
newSize = ( newSize + BLOCK_SIZE) & ( ~ (BLOCK_SIZE -1));
SetHandleSize( liste->liste, (Size)newSize);
if( MemError())
SysErr( MemError(), 0);
liste->nrBytes = newSize;
}
liste->size = nrElems;
} /* SizeListe() */
SysErr( err, type)
{
fprintf( stderr, "\nMemory allocation error, code= %d", err);
exit( 1);
}
SizeTempo( size)
{
SizeList( &tempoList, size, sizeof( TempoEvent));
} /* SizeTempo() */
SizePitch( voice, size)
{
SizeList( &pitchList[ voice], size, sizeof( PitchEvent));
} /* SizePitch() */
SizeInstrum( voice, size)
{
SizeList( &instrumList[ voice], size, sizeof( InstrumEvent));
} /* SizeInstrum() */
SizeVolume( voice, size)
{
SizeList( &volumeList[ voice], size, sizeof( VolumeEvent));
} /* SizeVolume() */
SizeNote( voice, size)
{
SizeList( ¬eList[ voice], size, sizeof( NoteEvent));
} /* SizeNote() */
SizeTimbre( size)
{
SizeList( &timbreList, size, sizeof( TimbreDef));
} /* SizeTimbre() */
TempoEvent * TempoPtr( pos)
{
return ( TempoEvent *) *tempoList.liste + pos;
} /* TempoPtr() */
VolumeEvent * VolumePtr( voice, pos)
{
return ( VolumeEvent *) *volumeList[ voice].liste + pos;
} /* VolumePtr() */
PitchEvent * PitchPtr( voice, pos)
{
return ( PitchEvent *) *pitchList[ voice].liste + pos;
} /* PitchPtr() */
InstrumEvent * InstrumPtr( voice, pos)
{
return ( InstrumEvent *) *instrumList[ voice].liste + pos;
} /* InstrumPtr() */
NoteEvent * NotePtr( voice, pos)
{
return ( NoteEvent *) *noteList[ voice].liste + pos;
} /* NotePtr() */
TimbreDef * TimbrePtr( pos)
{
return ( TimbreDef *) *timbreList.liste + pos;
} /* TimbrePtr() */
int MyLoadMelo( fileName)
char * fileName;
{
int fileId, i;
char buffer[ 255];
pitchBRange = 1;
strcpy( buffer, fileName);
/* strcat( buffer, musicFileExtension); */
fileId = open( buffer, O_RDONLY + O_RAW);
if( fileId == -1)
return 0;
duree_piece = 0;
if( 4 != read( fileId, buffer, 4)) /* skip file version, major & minor */
return 0;
if( 40 != read( fileId, buffer, 40)) /* skip filler field */
return 0;
if( 2 != read( fileId, &srcTickBeat, 2))
return 0;
if( 2 != read( fileId, &beatMeasure, 2))
return 0;
if( 5 != read( fileId, buffer, 5)) /* skip Y scale, X scale & filer */
return 0;
if( 1 != read( fileId, ¬PercusMode, 1))
return 0;
if( (90 + 38 + 15) != read( fileId, buffer, 90 + 38 + 15))
return 0; /* skip 3 filler field */
if( 4 != read( fileId, &basicTempo, 4))
return 0;
if( ! LoadTempo( fileId))
return 0;
for( i = 0; i < NR_VOICES; i++) {
if( 15 != read( fileId, buffer, 15)) /* skip filler */
return 0;
if( ! LoadNotes( fileId, i))
return 0;
if( 15 != read( fileId, buffer, 15))
return 0;
if( ! LoadInstrumEvt( fileId, i))
return 0;
if( 15 != read( fileId, buffer, 15))
return 0;
if( ! LoadVolume( fileId, i))
return 0;
if( 15 != read( fileId, buffer, 15))
return 0;
if( ! LoadPitch( fileId, i))
return 0;
}
LisMidiData( fileId);
close( fileId);
return 1;
} /* MyLoadMelo() */
int LoadPitch( fileId, voice)
{
int size, i, ok;
PitchEvent * pEvent;
if( 2 != read( fileId, &size, 2))
return 0;
SizePitch( voice, size);
pEvent = PitchPtr( voice, 0);
ok = 1;
for( i = 0; i < size && ok; i++, pEvent++)
ok = ( 6 == read( fileId, pEvent, 6));
return ok;
} /* LoadPitch() */
int LoadVolume( fileId, voice)
{
int size, i, ok;
VolumeEvent * vEvent;
if( 2 != read( fileId, &size, 2))
return 0;
SizeVolume( voice, size);
vEvent = VolumePtr( voice, 0);
ok = 1;
for( i = 0; i < size && ok; i++, vEvent++) {
ok = ( 6 == read( fileId, vEvent, 6));
}
return ok;
} /* LoadVolume() */
int LoadInstrumEvt( fileId, voice)
{
int size, ok, i;
InstrumEvent * iEvent;
if( 2 != read( fileId, &size, 2))
return 0;
ok = 1;
SizeInstrum( voice, size);
iEvent = InstrumPtr( voice, 0);
for( i = 0; i < size && ok; i++, iEvent++)
ok = ( 14 == read( fileId, iEvent, 14));
return ok;
} /* LoadInstrumEvt() */
int LoadNotes( fileId, voice)
{
NoteEvent * nEvent;
Time time, lastTime;
int count, ok;
time = 0;
if( 2 != read( fileId, &lastTime, 2))
return 0;
ok = 1;
count = 0;
SizeNote( voice, count);
while( time < lastTime && ok ) {
SizeNote( voice, count + 1);
nEvent = NotePtr( voice, count);
count++;
ok = ( 4 == read( fileId, nEvent, 4));
time += nEvent->duree;
}
duree_piece = max( duree_piece, lastTime);
return ok;
} /* LoadNotes() */
int LoadTempo( fileId)
{
int size, i, ok;
TempoEvent * tEvent;
if( 2 != read( fileId, &size, 2))
return 0;
SizeTempo( size);
tEvent = TempoPtr( 0);
ok = 1;
for( i = 0; i < size && ok; i++, tEvent++) {
ok = ( 6 == read( fileId, tEvent, 6));
}
return ok;
} /* LoadTempo() */
/*
If the .ROL file was written by the "Visual Composer/MIDI Supplement",
the pitch bend range is read from the file.
*/
LisMidiData( fileId)
{
struct midi_vars midiParam;
int i;
midiParam.midiVersion_ = 0;
read( fileId, &midiParam, sizeof( struct midi_vars));
if( midiParam.midiVersion_) {
/* le fichier contient le data MIDI ... */
pitchBRange = midiParam.pitchRange_;
}
} /* LisMidiData() */
/*
For each timbre reference in the .ROL file, search the index
of the bank file (.SND) for the timbre. If it exists, get the relative
position of the definition, if not, search in the current directory for
the timbre, and add it to the end of the bank file. The relative position
is the value saved with the command PROGRAM-CHANGE in the .MUS file.
If the timbre is not found, a warning message is printed on the screen,
and the timbre reference value is set to 0 ( first timbre of bank).
*/
LoadTimbres()
{
int voice, j, k, ok, nrDefs, fileId, timbPos;
int timbreDef[ TIMBRE_DEF_LEN];
InstrumEvent * iEvent;
char fileN[ 80];
char buff[ 10];
for( voice = 0; voice < NR_VOICES; voice++) {
iEvent = InstrumPtr( voice, 0);
for( j = instrumList[ voice].size; j; j--, iEvent++) {
iEvent->timbreIndex = 0; /* the first, by default */
if( GetTimbre( iEvent->instrumName, &timbPos, timbreDef, timbBank))
iEvent->timbreIndex = timbPos;
else {
setmem( timbreDef, TIMBRE_DEF_SIZE, 0);
strcpy( fileN, iEvent->instrumName);
strcat( fileN, instrumFileExtension);
fileId = open( fileN, O_RDONLY + O_RAW);
if( fileId != -1) {
read( fileId, buff, 2); /* skip instrum header */
read( fileId, timbreDef, TIMBRE_DEF_SIZE);
close( fileId);
AddTimbre( iEvent->instrumName, &timbPos, timbreDef, timbBank);
iEvent->timbreIndex = timbPos;
}
else {
fprintf( stderr, "\nInstrument not found: %s", fileN);
}
}
}
}
} /* LoadTimbres() */